#!/usr/bin/env python
# -*- coding:utf-8 -*-

import os
import os.path
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import image as img

class grid():
    def __init__(self):
        pass

class GridGraph():  #栅格图 GridGraph
    '''
    http://theory.stanford.edu/~amitp/GameProgramming/AStarComparison.html
    The pathfinding algorithms from computer science textbooks work on graphs 
    in the mathematical sense―a set of vertices with edges connecting them. 
    A tiled game map can be considered a graph with each tile being a vertex 
    and edges drawn between tiles that are adjacent to each other:
    For now, I will assume that we’re using two-dimensional grids.
    '''
    def __init__(self, map_file=None):
        self.load_basemap(map_file)
        self.cost_obstacle = 10000
        self.cost_empty = 1
        self.cost_dynamic = 10000

    @property 
    def cost_obstacle(self):
        return self._cost_obstacle

    @cost_obstacle.setter
    def cost_obstacle(self, cost=10000):
        self._cost_obstacle = cost

    @property
    def cost_empty(self):
        return self._cost_empty

    @cost_empty.setter
    def cost_empty(self, cost=1):
        self._cost_empty = cost

    @property
    def cost_dynamic(self):
        self._cost_dynamic

    @cost_dynamic.setter
    def cost_dynamic(self, cost=10000):
        self._cost_dynamic = cost

    @property
    def basemap(self): 
        return self._basemap

    @basemap.setter
    def basemap(self, basemap):
        self._basemap = basemap

    @property
    def size(self):
        return self._size

    @size.setter
    def size(self, size):
        self._size = size

    @property
    def dynamic(self):
        return self._dynamic

    @dynamic.setter
    def dynamic(self, dynamic):
        if isinstance(dynamic, list):
            self._dynamic = dynamic

    def load_basemap(self, map_file):
        if os.path.exists(map_file):
            temp_map = img.read(map_file)
            temp_map = temp_map[:, :, 0]
            self.basemap = temp_map
            self.size = temp_map.size
            # self.add_grid_attrs("basemap")
        
    def show_basemap(self):
        plt.axis('off')
        plt.gcf().set_size_inches(12, 8)
        plt.imshow(self.basemap, cmap='Greys_r')
    
    def is_empty(self, pos):
        if self.valid_pos(pos):
            if self.basemap[pos] == 1:
                return True
        return False

    def is_obstacle(self, pos):
        return not self.is_empty

    def have_dynamic(self, pos):
        return pos in self.dynamic

    def valid_pos(self, pos):
        if 0 <= pos[0] < self.shape[0] and 0 <= pos[1] < self.shape[1]:
            return True
        else:
            return False

    @property
    def cell(self, pos, name=None, attrs=None):
        if attrs is None:
            attrs = self.grid_attrs
        cell_dict = {}
        if self.valid_pos(pos):
            cell_dict["pos"] = pos
            cell_dict["name"] = name if name else "{}-{}".format(pos[0], pos[1])
            for attr in attrs:
                if hasattr(self, attr):
                    cell_dict[attr] = getattr(self, attr)[pos[0], pos[1]]
        return cell_dict

    def arc(self, from_u, to_v):
        arc_dict = {}
        arc_dict["from"] = from_u
        arc_dict["to"] = to_v
        pos_dist = ((from_u[0] - to_v[0]) ** 2 + (from_u[1] - to_v[1]) ** 2) ** 0.5
        arc_dict["cost"] = pos_dist * self.cost_empty
        if self.is_obstacle(from_u) or self.is_obstacle(to_v):
            arc_dict["cost"] = self.cost_obstacle
        if self.have_dynamic(from_u) or self.have_dynamic(to_v):
            arc_dict["cost"] = self.cost_dynamic
        return arc_dict

    def neighbors(self, pos):
        neighbors = []
        for i in [-1, 0, 1]:
            for j in [-1, 0, 1]:
                if i == 0 and j == 0:
                    continue
                new_pos = (pos[0]+i, pos[1]+j)
                if self.valid_pos(new_pos):
                    neighbors.append(new_pos)
        return neighbors 

if __name__ == "__main__":
    pass